<!--
    卡片风格的文件上传组件，主要用于一些小文件的上传，暂不支持分组上传,
    如果一个页面上有多个该组件实例，需要指定为不同的uploadId

    用法：<f7-file-upload :params="uploadParams" accept="image/png,image/jpeg" extensions="png,jpg,jpeg" title="资质证书" uploadId="files1"></f7-file-upload>

    备注：params，url后的请求参数，JSON格式，比如上面的
                uploadParams = { dataKey: 'xx', type: 'company' }
        accept，接受什么样的文件
        extensions，接受什么样的文件后缀
        title，显示的标题
        uploadId，默认值files，如果一个页面上有多个该组件实例，需要指定为不同的uploadId
 -->
<template>
    <f7-card style="margin: 10px auto">
        <f7-card-header>
            <span>{{ title }}</span>
            <span>
                <file-upload name="file"
                             class="button"
                             :input-id="uploadId"
                             :uploadAuto="uploadAuto"
                             @input-file="inputFile"
                             @input-filter="inputFilter"
                             :multiple="multiple"
                             :data="params"
                             :extensions="extensions"
                             :accept="accept"
                             :size="size"
                             :post-action="postUrl"
                             v-model="uploadFiles"
                             :ref="uploadId">上传</file-upload>
            </span>
        </f7-card-header>
        <f7-card-content>
            <f7-list media-list>
                <f7-list-item style="padding-left: 0"
                              link="#"
                              v-for="(file, index) in uploadFiles"
                              :key="file.id || file.attachmentId"
                              @click="operate(file, index)">
                    <template v-if="Object.keys(file).includes('response')">
                        <div v-if="file.response"
                             slot="title">
                            {{ file.name.lastIndexOf(".") == -1 ? file.name + ext : file.name }}
                        </div>
                        <img v-if="file.response"
                             slot="media"
                             :src="getThumb(file) | mapStatic"
                             width="40" />
                        <div v-if="file.response"
                             slot="subtitle">
                            <span>{{ file.size | fileSize }}</span>
                            <span class="right text-color-red"
                                  v-if="file.error">{{ formatError(file) }}</span>
                            <span class="right"
                                  v-else-if="file.active">上传中...{{ file.progress }}%</span>
                            <span class="right"
                                  v-else-if="file.response && file.response.success">上传成功</span>
                            <span class="right"
                                  v-else-if="file.response && !file.response.success">上传失败</span>
                            <span class="right"
                                  v-else>等待中...</span>
                        </div>
                        <f7-progressbar v-if="file.response"
                                        slot="text"
                                        color="red"
                                        :progress="parseFloat(file.progress)"></f7-progressbar>
                    </template>
                    <template v-else>
                        <div v-if="file.attachmentId"
                             slot="title">{{ file.fileName }}</div>
                        <img v-if="file.attachmentId"
                             slot="media"
                             :src="getThumbPng(file.fileType) | mapStatic"
                             width="40" />
                        <div v-if="file.attachmentId"
                             slot="subtitle">
                            <span>{{ file.fileSize | fileSize }}</span>
                        </div>
                    </template>
                </f7-list-item>
            </f7-list>
        </f7-card-content>
    </f7-card>
</template>
<script>
import ImageCompressor from "image-compressor.js";
import FileUpload from "vue-upload-component";
import formatter from "../framework/formatter";
import Config from "../config";
import Upload from "../framework/upload";

export default {
    components: {
        FileUpload
    },
    props: {
        params: {
            type: Object,
            default: () => ({})
        },
        extensions: {
            type: String,
            default: ""
        },
        accept: {
            type: String,
            default: ""
        },
        multiple: {
            type: Boolean,
            default: true
        },
        size: {
            type: Number,
            default: 1024 * 1024 * 10
        },
        chunkAction: {
            type: String,
            default: "/api/base/ChunkUpload/upload"
        },
        uploadAuto: {
            type: Boolean,
            default: true
        },
        title: {
            type: String,
            default: ""
        },
        uploadId: {
            type: String,
            default: "file"
        },
        initFile: {
            type: Object
        },
        autoCompress: {
            type: Number,
            default: 300 * 1024,
        }
    },
    data () {
        return {
            downUrl: "/api/base/fileupload/downFile",
            getUrl: "/api/base/fileupload/getFiles",
            deleteUrl: "/api/base/fileupload/delFile",
            postUrl: "/api/base/fileupload/uploadFile",
            ext: "",
            uploadFiles: [],
            actionTitle: "",
            actionFileKey: "",
            operateFileIndex: null
        };
    },
    methods: {
        operate (file, index) {
            let self = this;

            if (file.attachmentId || (file.response && file.response.parameters.file)) {
                self.actionFileKey = file.attachmentId;
                self.actionTitle = file.fileName;
                if (!self.actionFileKey) {
                    let respFile = file.response.parameters.file;
                    self.actionFileKey = respFile.key;
                    self.actionTitle = file.name;
                }

                self.operateFileIndex = index;
            } else {
                self.$f7.dialog.alert(
                    "文件" + file.name + "没有上传成功，无法操作",
                    function () {
                        self.uploadFiles.splice(self.operateFileIndex, 1);
                    }
                );
                return;
            }

            self.$f7.actions
                .create({
                    buttons: [
                        {
                            text: self.actionTitle,
                            label: true
                        },
                        {
                            text: "删除",
                            color: "red",
                            onClick: function () {
                                self.$f7.dialog.confirm("确定要删除该文件吗？", "删除", () => {
                                    // 文件可能因类型不符合而没有成功上传，此时直接从页面上删除
                                    if (!self.actionFileKey) {
                                        self.$f7.dialog.toast("删除成功");
                                        self.uploadFiles.splice(self.operateFileIndex, 1);
                                        return;
                                    }
                                    self.$f7.preloader.show();
                                    self.$f7.request.post(
                                        Config.api.delFile,
                                        { attachmentId: self.actionFileKey },
                                        r => {
                                            r = JSON.parse(r);
                                            self.$f7.preloader.hide();
                                            if (r && r.success) {
                                                self.uploadFiles.splice(self.operateFileIndex, 1);
                                                self.$f7.dialog.toast("删除成功");
                                            } else {
                                                self.$f7.dialog.toast(r.message || "删除失败");
                                            }
                                        }
                                    );
                                });
                            }
                        }
                    ]
                })
                .open();
        },
        getThumb (file) {
            let i = file.name.lastIndexOf(".");
            if (i != -1) {
                let extension = file.name.substring(i);
                return this.getThumbPng(extension);
            }
            if (this.ext) {
                return (
                    "/static/img/file/" + this.ext.substr(1, this.ext.length) + ".png"
                );
            }
            return "/static/img/file/default.png";
        },
        getThumbPng (fileExt) {
            if (
                fileExt &&
                ".avi,.doc,.docx,.jpg,.mp4,.pdf,.png,.ppt,.pptx,.rar,.txt,.xls,.xlsx,.zip"
                    .split(",")
                    .includes(fileExt.toLowerCase())
            ) {
                return "/static/img/file/" + fileExt.toLowerCase().substr(1) + ".png";
            }
            if (this.ext) {
                return (
                    "/static/img/file/" + this.ext.substr(1, this.ext.length) + ".png"
                );
            }
            return "/static/img/file/default.png";
        },
        formatError (file) {
            var error = "上传失败";
            switch (file.error) {
                case "size":
                    error = "文件太大，不超过" + formatter.formatFileSize(this.size);
                    break;
                case "extension":
                    error = "文件类型不符，只允许" + this.accept;
                    break;
                case "timeout":
                    error = "网络超时";
                    break;
                case "abort":
                    error = "用户放弃";
                    break;
                case "network":
                    error = "网络连接失败";
                    break;
                case "server":
                    error = "服务器错误";
                    break;
                case "denied":
                    error = "请求无效";
                    break;
                default:
                    error = "上传失败";
                    break;
            }
            return error;
        },
        inputFilter (newFile, oldFile, prevent) {
            if (newFile && !oldFile) {
                let self = this;
                let name = newFile.file.name;

                if (newFile.file.type == "" && window.FileReader) {
                    var reader = new FileReader();
                    reader.addEventListener("load", function (e) {
                        var typesMap = {
                            doc: "d0 cf 11 e0 a1 b1 1a e1",
                            docx: "50 4b 03 04",
                            pdf: "25 50 44 46"
                        };

                        var arrayBuffer = e.target.result;
                        if (arrayBuffer && arrayBuffer.byteLength >= 4) {
                            var slice = arrayBuffer.slice(0, 4);
                            var view = new Uint8Array(slice);
                            var arr = [];
                            view.forEach(function (v) {
                                arr.push(v.toString(16));
                            });
                            if (typesMap.doc.indexOf(arr.join(" ")) != -1) {
                                self.ext = ".doc";
                            }
                            if (typesMap.docx.indexOf(arr.join(" ")) != -1) {
                                self.ext = ".docx";
                            }
                            if (typesMap.pdf.indexOf(arr.join(" ")) != -1) {
                                self.ext = ".pdf";
                            }
                        }
                    });

                    reader.readAsArrayBuffer(newFile.file);
                }
                // Before adding a file
                // 添加文件前
                // Filter system files or hide files
                // 过滤系统文件 和隐藏文件
                if (/(\/|^)(Thumbs\.db|desktop\.ini|\..+)$/.test(newFile.name)) {
                    return prevent();
                }
                // Filter php html js file
                // 过滤 php html js 文件
                if (/\.(php5?|html?|jsx?)$/i.test(newFile.name)) {
                    return prevent();
                }
                // Automatic compression
                // 自动压缩
                if (
                    !window.plus &&
                    newFile.file &&
                    newFile.type.substr(0, 6) === "image/" &&
                    this.autoCompress > 0 &&
                    this.autoCompress < newFile.size
                ) {
                    newFile.error = "compressing";
                    const imageCompressor = new ImageCompressor(null, {
                        convertSize: Infinity,
                        maxWidth: 512,
                        maxHeight: 512
                    });
                    imageCompressor
                        .compress(newFile.file)
                        .then(file => {
                            this.$refs[this.uploadId].update(newFile, {
                                error: "",
                                file,
                                size: file.size,
                                type: file.type
                            });
                        })
                        .catch(err => {
                            this.$refs[this.uploadId].update(newFile, {
                                error: err.message || "compress"
                            });
                        });
                }
            }
            if (newFile && (!oldFile || newFile.file !== oldFile.file)) {
                // Create a blob field
                // 创建 blob 字段
                newFile.blob = "";
                let URL = window.URL || window.webkitURL;
                if (URL && URL.createObjectURL) {
                    newFile.blob = URL.createObjectURL(newFile.file);
                }
                // Thumbnails
                // 缩略图
                newFile.thumb = "";
                if (newFile.blob && newFile.type.substr(0, 6) === "image/") {
                    newFile.thumb = newFile.blob;
                }
            }
        },
        // add, update, remove File Event
        inputFile (newFile, oldFile) {
            if (newFile && oldFile) {
                // update
                if (newFile.active && !oldFile.active) {
                    // beforeSend
                    // min size
                    if (
                        newFile.size >= 0 &&
                        this.minSize > 0 &&
                        newFile.size < this.minSize
                    ) {
                        this.$refs[this.uploadId].update(newFile, { error: "size" });
                    }
                }
                if (newFile.progress !== oldFile.progress) {
                    // progress
                }
                if (newFile.error && !oldFile.error) {
                    // error
                    this.$f7.dialog.toast("文件上传失败");
                }
                if (newFile.success && !oldFile.success) {
                    // success
                    let rep = newFile.response;
                    if (Object.keys(rep).includes('success') && rep.success) {
                        // 上传成功
                        this.$emit("success", newFile);
                        // this.$f7.dialog.toast(`文件上传成功`);
                    } else {
                        // 上传失败
                        this.$f7.dialog.alert(newFile.response.message || '服务器不允许该文件上传');
                        this.uploadFiles.pop();
                    }
                }
                // if (newFile.success && !oldFile.success) {
                //   // success
                //   let fs = newFile.response.files;
                //   if (fs && fs[0].error) {
                //     this.$f7.dialog.toast(`${fs[0].message}`);
                //     let ind = this.uploadFiles.findIndex(f => {
                //       return f.id && f.id == newFile.id;
                //     });
                //     if (ind != -1) {
                //       this.uploadFiles.splice(ind, 1);
                //     }
                //   } else {
                //     this.$emit("success", newFile);
                //     this.$f7.dialog.toast(`文件上传成功`);
                //   }
                // }
            }
            if (!newFile && oldFile) {
                // remove
                if (oldFile.success && oldFile.response.id) {
                    // $.ajax({
                    //   type: 'DELETE',
                    //   url: '/upload/delete?id=' + oldFile.response.id,
                    // })
                }
            }
            // Automatically activate upload
            if (
                Boolean(newFile) !== Boolean(oldFile) ||
                oldFile.error !== newFile.error
            ) {
                if (this.uploadAuto && !this.$refs[this.uploadId].active) {
                    this.$refs[this.uploadId].active = true;
                }
            }
        }
    },
    created () {
        // 打包时不需要
        // this.getUrl = Config.api.getUrl;
        this.$f7.request.post(this.getUrl, this.params, r => {
            r = JSON.parse(r);
            if (r && r.success) {
                this.uploadFiles = r.parameters.files || [];
            } else {
                this.$framework.$f7.dialog.toast("获取文件失败");
            }
        });
    },
    mounted () {
        // if (window.plus) {
        //   this.postUrl = Config.api.upload;
        // }
        if (this.initFile) {
            this.filesJson[this.uploadId].push(this.initFile);
        }
    }
};
</script>
<style scoped>
.chunk-loading {
    margin: -12px;
    display: flex;
    width: calc(100% + 24px);
}
.chunk-loading .chunk-loading-part {
    height: 25px;
    line-height: 25px;
    flex: 1;
    background: #ccc;
    font-size: 14px;
    color: white;
    text-align: center;
}
.chunk-loading .chunk-loading-part.chunk-loading-part__uploaded {
    background: #28a745;
}
.file-uploads {
    width: 100%;
}
</style>
